package com.bowen.demo.demo001.comm;

import java.util.*;
import java.util.concurrent.*;

/**
 * <h3>java-study</h3>
 * <p>多线程实现方式</p>
 * @author : zhang.bw
 * @date : 2021-03-16 17:53
 **/
public class CommThread {

	public static void main(String[] args) {
		CommThread commThread = new CommThread();
		commThread.test1(); // 实现Runnable接口创建线程
		commThread.test2(); // Executors线程池创建线程-有返回值
		commThread.test3(); // Executors线程池创建线程-无返回值
		commThread.test4(); // ThreadPoolExecutor线程池创建线程
		commThread.test5(); // Executors线程池创建线程的四种方式
		commThread.test6(); // ThreadPoolExecutor线程池创建线程-无返回值
		commThread.test7(); // ThreadPoolExecutor线程池创建线程-有返回值
	}


	/**
	 * =============================实现Runnable接口创建线程 start=============================
	 */
	public void test1() {

		// 实现Runnable接口
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("实现Runnable接口创建线程!");
			}
		}).start();

	}
	// ==============================实现Runnable接口创建线程 end================================


	/**
	 *  ==========================Executors线程池创建线程-有返回值 start===========================
	 */
	public  void test2() {

		// 创建一个线程池
		ExecutorService executorService = Executors.newCachedThreadPool();

		// 传参
		List<String> list = new ArrayList<>();
		try {
			// 执行任务
			Future<Map> future = executorService.submit(new MyTest2(list));
			// 关闭线程池
			executorService.shutdown();
			// 返回结果
			System.out.println(future.get());
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 执行业务，有返回值
	 */
	class MyTest2 implements Callable<Map> {

		private List<String>  li;

		public MyTest2(List<String>  list) {
			this.li = list;
		}

		@Override
		public Map call() throws Exception {
			Map<String,Object> result = new HashMap<>();
			// TODO 具体业务逻辑
			// ......
			return result;
		}
	}
	// ============================Executors线程池创建线程-有返回值 end=============================


	/**
	 * ============================Executors线程池创建线程-无返回值 start=============================
	 */
	public void test3(){

		// 传参
		List<String> list = new ArrayList<>();

		// 创建一个线程池
		ExecutorService executorService = Executors.newCachedThreadPool();
		// 执行任务
		executorService.execute(new MyTest3(list));
		//关闭线程池
		executorService.shutdown();
	}

	/**
	 * 执行业务-无返回值
	 */
	class MyTest3 implements Runnable {

		private List<String>  li;

		public MyTest3(List<String>  list) {
			this.li = list;
		}

		@Override
		public void run() {
			// TODO 具体业务逻辑
			// ......
			System.out.println(li);
		}
	}
	// ============================Executors线程池创建线程-无返回值 end=============================

	/**
	 * ===========================ThreadPoolExecutor线程池创建线程 start===========================
	 */
	public void test4(){

		//核心线程数
		int corePoolSize = 3;
		//最大线程数
		int maximumPoolSize = 6;
		//超过 corePoolSize 线程数量的线程最大空闲时间
		long keepAliveTime = 2;
		//以秒为时间单位
		TimeUnit unit = TimeUnit.SECONDS;
		//创建工作队列，用于存放提交的等待执行任务
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(2);
		ThreadPoolExecutor threadPoolExecutor = null;
		try {
			//创建线程池
			threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,
					maximumPoolSize,
					keepAliveTime,
					unit,
					workQueue,
					new ThreadPoolExecutor.CallerRunsPolicy());


			//循环提交任务
			for (int i = 0; i < 9; i++) {
				//提交任务的索引
				final int index = (i + 1);
				threadPoolExecutor.submit(() -> {
					//线程打印输出
					System.out.println("大家好，我是线程：" + index);
					try {
						//模拟线程执行时间，10s
						Thread.sleep(10000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				});
				//每个任务提交后休眠500ms再提交下一个任务，用于保证提交顺序
				Thread.sleep(500);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			threadPoolExecutor.shutdown();
		}

	}
	// ===========================ThreadPoolExecutor线程池创建线程 end===========================


	/**
	 * ==========================Executors线程池创建线程的四种方式 start===========================
	 */
	public void test5(){

		Long start = System.currentTimeMillis();
		final Random random = new Random();
		final List<Integer> list = new ArrayList<>();

		// 通过静态方法创建出的线程都实现了ExecutorService接口。常用的方法包括：

		//（快）创建一个可缓存的线程池，调用execute方法将重用以前创建的线程，如果没有可用线程则创建一个新的线程并添加到池中。终止并移除那些已经存在60s未被使用的线程。
		// 同步队列（队列本质是存储） SynchronousQueue（同步队列） 一次存一个，创建一个Task消费后，才会创建第二个Task
		// TASK -》线程 -》CPU  CPU会飙到100%，不会出现内存溢出OOM
		ExecutorService executorService1 = Executors.newCachedThreadPool();

		//（慢）创建一个固定数目的线程池
		// 无界队列LinkedBlockingQueue 比较占用空间，一批10个（nThreads）执行
		// 会出现内存溢出OOM,因为无界队列,队列无限长 N个 Task 都压入队列
		ExecutorService executorService2 = Executors.newFixedThreadPool(10);


		//（最慢）创建一个单线程化的线程池
		// 无界队列LinkedBlockingQueue 线程池里只有一个线程
		ExecutorService executorService3 = Executors.newSingleThreadExecutor();

		// 创建一个定时及周期性执行任务的线程池
		ExecutorService executorService4 = Executors.newScheduledThreadPool(10);

		try {
			//方式一写法
			for (int i=1;i<=100000;i++){
				executorService1.execute(new MyTest5(i));
			}

			System.out.println("方式一结束");

			//方式二写法
			for (int i=1;i<=100000;i++){
				executorService1.execute(new Runnable() {
					@Override
					public void run() {
						list.add(random.nextInt());
					}
				});
			}
			executorService1.shutdown();
			executorService1.awaitTermination(1,TimeUnit.DAYS);
			System.out.println("方式二结果："+list.size() + "条");

			Long end = System.currentTimeMillis();
			Long time = end -start;
			System.out.println("耗时："+time);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}


	}

	class MyTest5 implements Runnable {

		int i;

		public MyTest5(int li) {
			this.i = li;
		}

		@Override
		public void run() {
			//System.out.println(Thread.currentThread().getName()+"第"+ i + "个");
		}
	}
	// ==========================Executors线程池创建线程的四种方式 end=============================


	/**
	 * ========================ThreadPoolExecutor线程池创建线程 无返回值 start=======================
	 */
	public void test6(){

		Long start = System.currentTimeMillis();
		final Random random = new Random();
		final List<Integer> list = new ArrayList<>();

		// 自定义线程池
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,50,
				0,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(100000));

		//使用ThreadPoolExecutor.execute(Runnable command)方法提交任务时，当线程池中正在使用的线程数达到了设置的最大的值（50），而且队列已（100000），就会报错。

		try {
			//方式一写法
			for (int i=1;i<=10000000;i++){
				if(threadPoolExecutor.getActiveCount()<50){
					threadPoolExecutor.execute(new MyTest6(i));
				}
			}
			System.out.println("方式一结束");

			Long end1 = System.currentTimeMillis();
			Long time1 = end1 -start;
			System.out.println("耗时："+time1);

			//方式二写法
			for (int i=1;i<=10000000;i++){
				if(threadPoolExecutor.getActiveCount()<50) {
					threadPoolExecutor.execute(new Runnable() {
						@Override
						public void run() {
							list.add(random.nextInt());
						}
					});
				}
			}
			threadPoolExecutor.shutdown();
			threadPoolExecutor.awaitTermination(1,TimeUnit.DAYS);
			System.out.println("方式二结果："+list.size() + "条");

			Long end2 = System.currentTimeMillis();
			Long time2 = end2 -start;
			System.out.println("耗时："+time2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	class MyTest6 implements Runnable {

		int i;

		public MyTest6(int li) {
			this.i = li;
		}

		@Override
		public void run() {
			//System.out.println(Thread.currentThread().getName()+"第"+ i + "个");
		}
	}
	// ==========================ThreadPoolExecutor线程池创建线程 无返回值 end========================


	/**
	 * ========================ThreadPoolExecutor线程池创建线程 有返回值 start=======================
	 */
	public void test7(){

		Long start = System.currentTimeMillis();
		final Random random = new Random();
		final List<Integer> list1 = new ArrayList<>();
		final List<Integer> list2 = new ArrayList<>();

		// 自定义线程池
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,
				0,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));

		try {
			//方式一写法
			for (int i=1;i<=1000000;i++){
				try {
					Future<List> result = threadPoolExecutor.submit(new MyTest7(i));
					//System.out.println("方式一的返回值："+result.get());
					list1.addAll(result.get());
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
			}
			System.out.println("方式一的结果："+list1.size()+"条");

			//方式二写法
			for (int i=1;i<=1000000;i++){
				try {
					Future<List> result = threadPoolExecutor.submit(new Callable<List>() {
						List<Integer> list = new ArrayList<>();
						@Override
						public List call() {
							//System.out.println(Thread.currentThread().getName());
							list.add(random.nextInt());
							return list;
						}
					});
					//System.out.println("方式二的返回值："+result.get());
					list2.addAll(result.get());
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
			}
			threadPoolExecutor.shutdown();
			threadPoolExecutor.awaitTermination(1,TimeUnit.DAYS);
			System.out.println("方式二的结果："+list2.size()+"条");

			Long end = System.currentTimeMillis();
			Long time = end -start;
			System.out.println("耗时："+time);

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	class MyTest7 implements Callable<List> {

		int i;
		List<Integer> list = new ArrayList<>();

		public MyTest7(int li) {
			this.i = li;
		}

		@Override
		public List call() {
			//System.out.println(Thread.currentThread().getName()+"第"+ i + "个");
			list.add(i);
			return list;
		}
	}
	// ==========================ThreadPoolExecutor线程池创建线程 有返回值 end============================

}
